import random
import shutil

from PIL import Image
from django.shortcuts import render

# Create your views here.
import geopandas as gpd
import ezdxf
from django.http import JsonResponse, HttpResponse
import os
from django.views.decorators.http import require_http_methods, require_POST, require_GET
import requests
from shapely.geometry import box

from gis_handle.util import get_combined_bbox, get_gaode_map_image, generate_frame, generate_legend

# 高德地图 API_KEY
GAODE_API_KEY = "2a4d111f2cf8fac38dd67b856fca0cbc"


@require_http_methods(["POST", "GET"])
def gis_test(request):
    return HttpResponse("这是gis_test测试方法")


# 主函数
@require_http_methods(["POST"])
def shp_to_dwg(request):
    # 获取post提交值
    shp_folder = request.POST.get('shp_folder')
    output_dwg = request.POST.get('output_dwg')
    output_dxf_file = request.POST.get('output_dxf_file')
    zonestr = request.POST.get('zone')

    # 尝试将 zone 转换为整数
    try:
        zone = int(zonestr)
    except (ValueError, TypeError):
        return JsonResponse({'status': 'error', 'message': '传入的分度带 zone 不是有效的整数'})

    # 获取综合边界范围
    bbox = get_combined_bbox(shp_folder)
    print("综合边界范围:", bbox)

    # 创建DWG文件
    doc = ezdxf.new("R2010", setup=True)
    doc.units = ezdxf.InsertUnits.Meters

    # 底图
    msp = doc.modelspace()
    # 获取高德地图底图
    basemap_path = get_gaode_map_image(bbox, zone)
    # 复制底图到 DXF 文件所在目录
    dxf_dir = os.path.dirname(output_dxf_file)
    new_basemap_path = os.path.join(dxf_dir, os.path.basename(basemap_path))
    shutil.copy2(basemap_path, new_basemap_path)
    # 使用相对路径插入底图
    relative_basemap_path = os.path.relpath(new_basemap_path, dxf_dir)
    # 获取图像的像素尺寸
    with Image.open(basemap_path) as img:
        image_width, image_height = img.size  # 获取图像的像素尺寸
    # 插入底图
    image_def = doc.add_image_def(
        filename=relative_basemap_path,  # 图像文件路径
        size_in_pixel=(image_width, image_height))  # 图像的像素尺寸
    under_image = msp.add_image(
        image_def,  # 图像定义对象
        insert=(bbox[0], bbox[1]),  # 插入点
        size_in_units=(bbox[2] - bbox[0], bbox[3] - bbox[1])  # 图像大小
    )
    # 设置图像的褪色度来模拟透明度，范围 0-100，值越大越透明
    fade_value = 45  # 可根据需要调整此值
    under_image.dxf.fade = fade_value

    # 处理每个SHP文件
    # 定义一个颜色列表，包含常见的颜色代码
    color_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    layers = []
    for root, dirs, files in os.walk(shp_folder):
        for file in files:
            if file.endswith(".shp"):
                shp_file = os.path.join(root, file)
                layer_name = os.path.splitext(file)[0]
                gdf = gpd.read_file(shp_file)
                # 检查源数据是否有坐标系定义
                if gdf.crs is None:
                    return JsonResponse({'status': 'error', 'message': f'{shp_file} 没有定义坐标系，无法进行转换'})
                # 将数据转换为指定坐标系
                # try:
                #     gdf = gdf.to_crs(epsg=4523)
                # except Exception as e:
                #     return JsonResponse({'status': 'error', 'message': f'坐标系转换失败：{str(e)}'})
                color = random.choice(color_list)  # 随机颜色
                # 计算线宽
                linewidth = 25 + (len(layers)) * 3  # 线宽根据图层顺序递增，单位为 1/100mm
                # 限制线宽在 0.3mm（30）到 0.8mm（80）之间
                linewidth = max(28, min(linewidth, 50))
                # 创建新图层并设置颜色
                layer = doc.layers.new(name=layer_name, dxfattribs={'lineweight': linewidth})
                layer.color = color # 设置图层颜色
                mspy = doc.modelspace()
                # 添加几何图形到DWG
                for geometry in gdf.geometry:
                    if geometry.geom_type == 'Point':
                        #print(f"添加点: ({geometry.exterior.coords})")
                        mspy.add_point(geometry.exterior.coords,
                                       dxfattribs={'layer': layer_name})
                    elif geometry.geom_type == "LineString":
                        #print(f"添加线: ({list(geometry.coords)})")
                        mspy.add_lwpolyline(list(geometry.coords),
                                            dxfattribs={'layer': layer_name})
                    elif geometry.geom_type == "Polygon":
                        points = list(geometry.exterior.coords)
                        mspy.add_lwpolyline(points, dxfattribs={'layer': layer_name})
                        # 设置填充色
                        hatch = mspy.add_hatch(color=color, dxfattribs={'layer': layer_name})
                        hatch.paths.add_polyline_path(points, is_closed=True)

                    # 可以继续添加其他几何类型的处理

                # 记录图层信息
                layers.append((layer_name, color, linewidth))

    # 生成图例
    generate_legend(doc, layers, bbox)
    # 生成图框
    generate_frame(doc, bbox)

    # 保存DWG文件
    doc.saveas(output_dxf_file)
    print(f"DWG文件已保存到: {output_dxf_file}")
    return JsonResponse({'status': 'success', 'message': f'多个 SHP 文件已转换为 DXF 文件: {output_dxf_file}'})


@require_http_methods(["POST"])
def gis_to_shp(request):
    input_gis_file = request.POST.get('input_gis_file')
    output_shp_file = request.POST.get('output_shp_file')
    target_srs = request.POST.get('target_srs', 'EPSG:4490')

    try:
        gdf = gpd.read_file(input_gis_file)
        gdf = gdf.to_crs(target_srs)
        gdf.to_file(output_shp_file)
        return JsonResponse({'status': 'success', 'message': f'GIS 数据已转换为 SHP 文件: {output_shp_file}'})
    except Exception as e:
        return JsonResponse({'status': 'error', 'message': str(e)})


@require_http_methods(["POST"])
def shp_to_dxf(request):
    shp_folder = request.POST.get('shp_folder')
    output_dxf_file = request.POST.get('output_dxf_file')

    # 输入参数验证
    if not shp_folder or not output_dxf_file:
        return JsonResponse({'status': 'error', 'message': '缺少必要参数：shp_folder 或 output_dxf_file'})

    try:
        doc = ezdxf.new('R2010')
        doc.units = ezdxf.InsertUnits.Meters

        # 初始化边界范围
        min_x = float('inf')
        min_y = float('inf')
        max_x = float('-inf')
        max_y = float('-inf')

        # 定义一个颜色列表，包含常见的颜色代码
        color_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]
        legend_items = {}
        for root, dirs, files in os.walk(shp_folder):
            for file in files:
                if file.endswith('.shp'):
                    shp_file = os.path.join(root, file)
                    layer_name = os.path.splitext(file)[0]
                    gdf = gpd.read_file(shp_file)
                    print(f"数据最小坐标: {gdf.total_bounds[:2]}")
                    print(f"数据最大坐标: {gdf.total_bounds[2:]}")
                    # 检查源数据是否有坐标系定义
                    if gdf.crs is None:
                        return JsonResponse({'status': 'error', 'message': f'{shp_file} 没有定义坐标系，无法进行转换'})

                    # 将数据转换为指定坐标系
                    # try:
                    #     gdf = gdf.to_crs(epsg=4523)
                    # except Exception as e:
                    #     return JsonResponse({'status': 'error', 'message': f'坐标系转换失败：{str(e)}'})

                    # 随机选择一个颜色
                    color = random.choice(color_list)
                    # 创建新图层并设置颜色
                    layer = doc.layers.new(name=layer_name)
                    layer.color = color

                    legend_items[layer_name] = color

                    msp = doc.modelspace()
                    for index, row in gdf.iterrows():
                        geom = row.geometry
                        if geom.geom_type == 'Point':
                            # 去掉分度带编号
                            x = float(str(geom.x)[2:])
                            y = geom.y
                            # 更新边界范围
                            min_x = min(min_x, x)
                            min_y = min(min_y, y)
                            max_x = max(max_x, x)
                            max_y = max(max_y, y)
                            # print(f"添加点: ({x}, {y})")
                            point = msp.add_point((x, y), dxfattribs={'layer': layer_name, 'color': color})
                            point.dxf.color = color
                        elif geom.geom_type == 'LineString':
                            points = []
                            for point in geom.coords:
                                # 去掉分度带编号
                                x = float(str(point[0])[2:])
                                y = point[1]
                                # 更新边界范围
                                min_x = min(min_x, x)
                                min_y = min(min_y, y)
                                max_x = max(max_x, x)
                                max_y = max(max_y, y)
                                points.append((x, y))
                            # print(f"添加线: ({points})")
                            linestring = msp.add_lwpolyline(points, dxfattribs={'layer': layer_name, 'color': color})
                            linestring.dxf.color = color
                        elif geom.geom_type == 'Polygon':
                            points = []
                            for point in geom.exterior.coords:
                                # 去掉分度带编号
                                x = float(str(point[0])[2:])
                                y = point[1]
                                points.append((x, y))
                                # 更新边界范围
                                min_x = min(min_x, x)
                                min_y = min(min_y, y)
                                max_x = max(max_x, x)
                                max_y = max(max_y, y)
                            polyline = msp.add_polyline2d(points, dxfattribs={'layer': layer_name})
                            polyline.dxf.color = color
                            # 设置填充色
                            hatch = msp.add_hatch(color=color, dxfattribs={'layer': layer_name})
                            hatch.paths.add_polyline_path(points, is_closed=True)

                        # 可以继续添加其他几何类型的处理

                        # 显示标注
                        if 'label' in gdf.columns:
                            label = row['label']
                            if geom.geom_type == 'Point':
                                text = msp.add_text(label, dxfattribs={'layer': layer_name})
                                text.dxf.insert = (float(str(geom.x)[2:]), geom.y, 0)

        bbox = box(min_x, min_y, max_x, max_y)
        # 高德地图 api_key
        # 获取地图截图
        map_image_path = get_map_screenshot(bbox, GAODE_API_KEY)

        # 新增：插入截图
        # 创建图像图层
        layer_image = doc.layers.new(name='Image')

        # 新增：生成图例
        legend_x = max_x - 20
        legend_y = min_y + 10
        legend_item_height = 2
        msp = doc.modelspace()
        for i, (layer_name, color) in enumerate(legend_items.items()):
            # 添加图例颜色方块
            square_points = [
                (legend_x, legend_y - i * legend_item_height),
                (legend_x + 1, legend_y - i * legend_item_height),
                (legend_x + 1, legend_y - (i + 1) * legend_item_height),
                (legend_x, legend_y - (i + 1) * legend_item_height)
            ]
            polyline = msp.add_polyline2d(square_points, dxfattribs={'layer': layer_name, 'color': color})
            hatch = msp.add_hatch(color=color, dxfattribs={'layer': layer_name})
            hatch.paths.add_polyline_path(square_points, is_closed=True)

            # 添加图例文字说明
            text = msp.add_text(layer_name, dxfattribs={'layer': layer_name, 'color': color})
            text.dxf.insert = (legend_x + 2, legend_y - (i + 0.5) * legend_item_height, 0)

        # 新增：在获取边界框后插入底图
        # 手动定义图像定义
        image_def = doc.add_image_def(filename=map_image_path, size_in_pixel=(1, 1))
        if map_image_path and os.path.exists(map_image_path):
            # 检查文件扩展名是否为支持的格式
            supported_extensions = ['.jpg', '.jpeg', '.png']
            file_extension = os.path.splitext(map_image_path)[1].lower()
            if file_extension not in supported_extensions:
                return JsonResponse({'status': 'error', 'message': f'不支持的图片格式: {file_extension}'})
            msp = doc.modelspace()
            insert_x = min_x + 1
            insert_y = min_y + 1
            msp.add_image(
                image_def=image_def,
                insert=(insert_x, insert_y),
                size_in_units=(5, 5),
                dxfattribs={'layer': 'Image'}
            )

        # 保存 DXF 文件
        doc.saveas(output_dxf_file)
        return JsonResponse({'status': 'success', 'message': f'多个 SHP 文件已转换为 DXF 文件: {output_dxf_file}'})
    except Exception as e:
        return JsonResponse({'status': 'error', 'message': str(e)})


def get_map_screenshot(bbox, api_key, map_type='amap'):
    if map_type == 'amap':
        # 构建请求 URL
        url = f"https://restapi.amap.com/v3/staticmap?location={bbox.centroid.x},{bbox.centroid.y}&zoom=10&size=1024*768&key={api_key}&markers=mid,,A:{bbox.bounds[0]},{bbox.bounds[1]}"
        print(f"请求 URL: {url}")  # 打印请求 URL，方便调试

        try:
            # 发送请求
            response = requests.get(url)

            # 检查响应状态码
            if response.status_code == 200:
                # 尝试解析响应内容，判断是否为 JSON 格式（错误信息通常为 JSON）
                try:
                    data = response.json()
                    if 'status' in data and data['status'] == '0':
                        print(f"请求失败，错误信息: {data.get('info', '未知错误')}")
                        return None
                except ValueError:
                    # 不是 JSON 格式，说明是正常的图片数据
                    pass

                # 保存图片
                map_image_path = 'map_screenshot.png'
                with open(map_image_path, 'wb') as f:
                    f.write(response.content)
                print(f"地图截图已保存到 {map_image_path}")
                return map_image_path
            else:
                print(f"请求失败，状态码: {response.status_code}")
                return None
        except requests.RequestException as e:
            print(f"请求发生异常: {e}")
            return None
    else:
        print(f"不支持的地图类型: {map_type}")
        return None


def shp_to_dxf_with_map(shp_folder, output_dxf_file, api_key):
    # 计算所有 SHP 文件的边界框
    all_bounds = []
    for root, dirs, files in os.walk(shp_folder):
        for file in files:
            if file.endswith('.shp'):
                shp_file = os.path.join(root, file)
                gdf = gpd.read_file(shp_file)
                all_bounds.append(gdf.total_bounds)

    minx = min([b[0] for b in all_bounds])
    miny = min([b[1] for b in all_bounds])
    maxx = max([b[2] for b in all_bounds])
    maxy = max([b[3] for b in all_bounds])
    bbox = box(minx, miny, maxx, maxy)

    # 获取地图截图
    map_image_path = get_map_screenshot(bbox, api_key)

    doc = ezdxf.new('R2010')
    msp = doc.modelspace()

    # 插入地图截图
    insert_point = (minx, miny)
    msp.add_image(filename=map_image_path, insert=insert_point,
                  size_in_units=(bbox.bounds[2] - bbox.bounds[0], bbox.bounds[3] - bbox.bounds[1]))

    # 处理 SHP 文件
    for root, dirs, files in os.walk(shp_folder):
        for file in files:
            if file.endswith('.shp'):
                shp_file = os.path.join(root, file)
                layer_name = os.path.splitext(file)[0]
                gdf = gpd.read_file(shp_file)
                layer = doc.layers.new(name=layer_name)
                for index, row in gdf.iterrows():
                    geom = row.geometry
                    if geom.geom_type == 'Point':
                        msp.add_point((geom.x, geom.y), dxfattribs={'layer': layer_name})
                        if 'label' in gdf.columns:
                            label = row['label']
                            msp.add_text(label, dxfattribs={'layer': layer_name}).set_pos((geom.x, geom.y))
                    elif geom.geom_type == 'LineString':
                        points = [(point[0], point[1]) for point in geom.coords]
                        msp.add_lwpolyline(points, dxfattribs={'layer': layer_name})

    doc.saveas(output_dxf_file)
    return output_dxf_file


# 自动生成图例信息
def add_legend(doc, msp, shp_folder):
    legend_x = 0
    legend_y = 0
    for root, dirs, files in os.walk(shp_folder):
        for file in files:
            if file.endswith('.shp'):
                layer_name = os.path.splitext(file)[0]
                # 添加图例符号（这里以点为例）
                msp.add_point((legend_x, legend_y), dxfattribs={'layer': 'Legend'})
                # 添加图例文本
                msp.add_text(layer_name, dxfattribs={'layer': 'Legend'}).set_pos((legend_x + 1, legend_y))
                legend_y -= 1


if __name__ == "__main__":
    # 创建测试用的 bbox 对象
    test_bbox = box(116.397128, 39.916527, 116.407128, 39.926527)
    # 替换为你的实际 API 密钥

    # 调用 get_map_screenshot 方法进行测试
    result = get_map_screenshot(test_bbox, GAODE_API_KEY)

    if result:
        print("测试成功，地图截图已保存。")
    else:
        print("测试失败，请检查 API 密钥和网络连接。")
